package org.nicocube.airain.domain.server.storable;

import java.util.List;

import org.nicocube.airain.domain.client.dao.NoPlayerException;
import org.nicocube.airain.domain.client.exception.DomainException;
import org.nicocube.airain.domain.server.dao.DomainDAO;
import org.nicocube.airain.domain.server.dao.DomainQuery;
import org.nicocube.airain.domain.server.dao.DomainRequest;
import org.nicocube.airain.domain.server.dao.DomainResultContainer;
import org.nicocube.airain.domain.server.dao.PersistenceAccessor;

import com.google.appengine.api.users.User;

public class PlayerDAO extends DomainDAO {

	public boolean exists(final User user) throws DomainException {
		final DomainResultContainer<Integer> result = new DomainResultContainer<Integer>();
		eval(countPlayer(user, result));
		return result.get() > 0;
	}

	DomainRequest countPlayer(final User user,
			final DomainResultContainer<Integer> result) {
		return new DomainRequest() {
			@Override
			public void playOn(PersistenceAccessor pm) throws DomainException {
				DomainQuery<Integer> query0 = pm.newQuery(Player.class)
						.withResult(Integer.class, "count(order)")
						.addCriteria("user", User.class, user);
				result.set(query0.execute());
			}
		};
	}

	abstract class PlayerByUserDomainRequest implements DomainRequest {
		private final User user;

		public PlayerByUserDomainRequest(User user) {
			this.user = user;
		}

		@Override
		public void playOn(PersistenceAccessor pm) throws DomainException {
			DomainQuery<Player> query0 = pm.newQuery(Player.class);
			query0.addCriteria("user", User.class, user);

			List<Player> r = query0.executeList();

			Player p = (Player) r.get(0);
			processResult(p);
		}

		protected abstract void processResult(Player p);
	}

	DomainRequest getIdByUser(final User user,
			final DomainResultContainer<Long> result) {
		return new PlayerByUserDomainRequest(user) {
			@Override
			protected void processResult(Player p) {
				result.set(p.getOrder());
			}
		};
	}

	public void save(final Player player) throws DomainException {
		eval(new DomainRequest() {
			@Override
			public void playOn(PersistenceAccessor pm) throws DomainException {
				pm.makePersistent(player);
			}
		});
	}

	public Player getByUser(final User user) throws DomainException {
		final DomainResultContainer<Player> result = new DomainResultContainer<Player>();
		eval(new DomainRequest() {
			@Override
			public void playOn(PersistenceAccessor pm) throws DomainException {
				DomainResultContainer<Integer> res = new DomainResultContainer<Integer>();
				countPlayer(user, res).playOn(pm);
				if (res.get() == 0)
					throw new NoPlayerException(user.getEmail());
			}
		}, new PlayerByUserDomainRequest(user) {
			@Override
			protected void processResult(Player p) {
				result.set(p);
			}
		});
		return result.get();
	}

}
